define("jquery-plugin/jcrop/2.0.4/jcrop-debug", [ "$-debug" ], function(require) {
    var jQuery = require("$-debug");
      (function($){
        'use strict';

        // Jcrop constructor
        var Jcrop = function(element,opt){
            var _ua = navigator.userAgent.toLowerCase();

            this.opt = $.extend({},Jcrop.defaults,opt || {});

            this.container = $(element);

            this.opt.is_msie = /msie/.test(_ua);
            this.opt.is_ie_lt9 = /msie [1-8]\./.test(_ua);

            this.container.addClass(this.opt.css_container);

            this.ui = {};
            this.state = null;
            this.ui.multi = [];
            this.ui.selection = null;
            this.filter = {};
            console.log(this);
            this.init();
            this.setOptions(opt);
            this.applySizeConstraints();
            this.container.trigger('cropinit',this);

            // IE<9 doesn't work if mouse events are attached to window
            if (this.opt.is_ie_lt9)
                this.opt.dragEventTarget = document.body;
        };


        // Jcrop static functions
        $.extend(Jcrop,{
            component: { },
            filter: { },
            stage: { },
            registerComponent: function(name,component){
                Jcrop.component[name] = component;
            },
            registerFilter: function(name,filter){
                Jcrop.filter[name] = filter;
            },
            registerStageType: function(name,stage){
                Jcrop.stage[name] = stage;
            },
            // attach: function(element,opt){{{
            attach: function(element,opt){
                var obj = new $.Jcrop(element,opt);
                return obj;
            },
            // }}}
            // imgCopy: function(imgel){{{
            imgCopy: function(imgel){
                var img = new Image;
                img.src = imgel.src;
                return img;
            },
            // }}}
            // imageClone: function(imgel){{{
            imageClone: function(imgel){
                return $.Jcrop.supportsCanvas?
                    Jcrop.canvasClone(imgel):
                    Jcrop.imgCopy(imgel);
            },
            // }}}
            // canvasClone: function(imgel){{{
            canvasClone: function(imgel){
                var canvas = document.createElement('canvas'),
                    ctx = canvas.getContext('2d');

                $(canvas).width(imgel.width).height(imgel.height),
                    canvas.width = imgel.naturalWidth;
                canvas.height = imgel.naturalHeight;
                ctx.drawImage(imgel,0,0,imgel.naturalWidth,imgel.naturalHeight);
                return canvas;
            },
            // }}}
            // propagate: function(plist,config,obj){{{
            propagate: function(plist,config,obj){
                for(var i=0,l=plist.length;i<l;i++)
                    if (config.hasOwnProperty(plist[i]))
                        obj[plist[i]] = config[plist[i]];
            },
            // }}}
            // getLargestBox: function(ratio,w,h){{{
            getLargestBox: function(ratio,w,h){
                if ((w/h) > ratio)
                    return [ h * ratio, h ];
                else return [ w, w / ratio ];
            },
            // }}}
            // stageConstructor: function(el,options,callback){{{
            stageConstructor: function(el,options,callback){

                // Get a priority-ordered list of available stages
                var stages = [];
                $.each(Jcrop.stage,function(i,e){
                    stages.push(e);
                });
                stages.sort(function(a,b){ return a.priority - b.priority; });
                // Find the first one that supports this element
                console.log(stages);
                for(var i=0,l=stages.length;i<l;i++){
                    if (stages[i].isSupported(el,options)){
                        console.log('支持的创建策略');
                        console.log(stages[i]);
                        console.log(i);
                        stages[i].create(el,options,function(obj,opt){
                            if (typeof callback == 'function') callback(obj,opt);
                        });
                        break;
                    }
                }
            },
            // }}}
            // supportsColorFade: function(){{{
            supportsColorFade: function(){
                return $.fx.step.hasOwnProperty('backgroundColor');
            },
            // }}}
            // wrapFromXywh: function(xywh){{{
            wrapFromXywh: function(xywh){
                var b = { x: xywh[0], y: xywh[1], w: xywh[2], h: xywh[3] };
                b.x2 = b.x + b.w;
                b.y2 = b.y + b.h;
                return b;
            }
            // }}}
        });

        var AbstractStage = function(){
        };

        $.extend(AbstractStage,{
            isSupported: function(el,o){
                // @todo: should actually check if it's an HTML element
                return true;
            },
            // A higher priority means less desirable
            // AbstractStage is the last one we want to use
            priority: 100,
            create: function(el,options,callback){
                var obj = new AbstractStage;
                obj.element = el;
                callback.call(this,obj,options);
            },
            prototype: {
                attach: function(core){
                    console.log(this);
                    this.init(core);
                    core.ui.stage = this;
                },
                triggerEvent: function(ev){
                    $(this.element).trigger(ev);
                    return this;
                },
                getElement: function(){
                    return this.element;
                },
                init: function (core) {
                    this.core = core;
                }
            }
        });
        Jcrop.registerStageType('Block',AbstractStage);


        var ImageStage = function(){
        };

        ImageStage.prototype = new AbstractStage();

        $.extend(ImageStage,{
            isSupported: function(el,o){
                if (el.tagName == 'IMG') return true;
            },
            priority: 90,
            create: function(el,options,callback){
                $.Jcrop.component.ImageLoader.attach(el,function(w,h){
                    var obj = new ImageStage;
                    obj.element = $(el).wrap('<div />').parent();

                    obj.element.width(w).height(h);
                    obj.imgsrc = el;

                    if (typeof callback == 'function')
                        callback.call(this,obj,options);
                });
            }
        });
        Jcrop.registerStageType('Image',ImageStage);


        var CanvasStage = function(){
            this.angle = 0;
            this.scale = 1;
            this.scaleMin = 0.2;
            this.scaleMax = 1.25;
            this.offset = [0,0];
        };

        CanvasStage.prototype = new ImageStage();

        $.extend(CanvasStage,{
            isSupported: function(el,o){
                if ($.Jcrop.supportsCanvas && (el.tagName == 'IMG')) return true;
            },
            priority: 60,
            create: function(el,options,callback){
                var $el = $(el);
                var opt = $.extend({},options);
                $.Jcrop.component.ImageLoader.attach(el,function(w,h){
                    var obj = new CanvasStage;
                    var w = $el.width();
                    var h = $el.height();
                    console.log('防止隐藏的元素获取高款款值有误差');
                    $el.width(w).height(h).hide();
                    obj.createCanvas(el,w,h);
                    $el.before(obj.element);
                    obj.imgsrc = el;
                    opt.imgsrc = el;

                    if (typeof callback == 'function'){
                        callback(obj,opt);
                        obj.redraw();
                    }
                });
            }
        });

        $.extend(CanvasStage.prototype,{
            // setOffset: function(x,y) {{{
            setOffset: function(x,y) {
                this.offset = [x,y];
                return this;
            },
            // }}}
            // setAngle: function(v) {{{
            setAngle: function(v) {
                this.angle = v;
                return this;
            },
            // }}}
            // setScale: function(v) {{{
            setScale: function(v) {
                this.scale = this.boundScale(v);
                return this;
            },
            // }}}
            boundScale: function(v){
                if (v<this.scaleMin) v = this.scaleMin;
                else if (v>this.scaleMax) v = this.scaleMax;
                return v;
            },
            createCanvas: function(img,w,h){
                this.width = w;
                this.height = h;
                this.canvas = document.createElement('canvas');
                this.canvas.width = w;
                this.canvas.height = h;
                this.$canvas = $(this.canvas).width('100%').height('100%');
                this.context = this.canvas.getContext('2d');
                this.fillstyle = "rgb(0,0,0)";
                this.element = this.$canvas.wrap('<div />').parent().width(w).height(h);
            },
            triggerEvent: function(ev){
                this.$canvas.trigger(ev);
                return this;
            },
            // clear: function() {{{
            clear: function() {
                this.context.fillStyle = this.fillstyle;
                this.context.fillRect(0, 0, this.canvas.width, this.canvas.height);
                return this;
            },
            // }}}
            // redraw: function() {{{
            redraw: function() {
                // Save the current context
                this.context.save();
                this.clear();

                // Translate to the center point of our image
                this.context.translate(parseInt(this.width * 0.5), parseInt(this.height * 0.5));
                // Perform the rotation and scaling
                this.context.translate(this.offset[0]/this.core.opt.xscale,this.offset[1]/this.core.opt.yscale);
                this.context.rotate(this.angle * (Math.PI/180));
                this.context.scale(this.scale,this.scale);
                // Translate back to the top left of our image
                this.context.translate(-parseInt(this.width * 0.5), -parseInt(this.height * 0.5));
                // Finally we draw the image
                this.context.drawImage(this.imgsrc,0,0,this.width,this.height);

                // And restore the updated context
                this.context.restore();
                this.$canvas.trigger('cropredraw');
                return this;
            },
            // }}}
            // setFillStyle: function(v) {{{
            setFillStyle: function(v) {
                this.fillstyle = v;
                return this;
            }
            // }}}
        });

        Jcrop.registerStageType('Canvas',CanvasStage);


        /**
         *  BackoffFilter
         *  move out-of-bounds selection into allowed position at same size
         */
        var BackoffFilter = function(){
            this.minw = 40;
            this.minh = 40;
            this.maxw = 0;
            this.maxh = 0;
            this.core = null;
        };
        $.extend(BackoffFilter.prototype,{
            tag: 'backoff',
            priority: 22,
            filter: function(b){
                var r = this.bound;

                if (b.x < r.minx) { b.x = r.minx; b.x2 = b.w + b.x; }
                if (b.y < r.miny) { b.y = r.miny; b.y2 = b.h + b.y; }
                if (b.x2 > r.maxx) { b.x2 = r.maxx; b.x = b.x2 - b.w; }
                if (b.y2 > r.maxy) { b.y2 = r.maxy; b.y = b.y2 - b.h; }

                return b;
            },
            refresh: function(sel){
                this.elw = sel.core.container.width();
                this.elh = sel.core.container.height();
                this.bound = {
                    minx: 0 + sel.edge.w,
                    miny: 0 + sel.edge.n,
                    maxx: this.elw + sel.edge.e,
                    maxy: this.elh + sel.edge.s
                };
            }
        });
        Jcrop.registerFilter('backoff',BackoffFilter);

        /**
         *  ConstrainFilter
         *  a filter to constrain crop selection to bounding element
         */
        var ConstrainFilter = function(){
            this.core = null;
        };
        $.extend(ConstrainFilter.prototype,{
            tag: 'constrain',
            priority: 5,
            filter: function(b,ord){
                if (ord == 'move') {
                    if (b.x < this.minx) { b.x = this.minx; b.x2 = b.w + b.x; }
                    if (b.y < this.miny) { b.y = this.miny; b.y2 = b.h + b.y; }
                    if (b.x2 > this.maxx) { b.x2 = this.maxx; b.x = b.x2 - b.w; }
                    if (b.y2 > this.maxy) { b.y2 = this.maxy; b.y = b.y2 - b.h; }
                } else {
                    if (b.x < this.minx) { b.x = this.minx; }
                    if (b.y < this.miny) { b.y = this.miny; }
                    if (b.x2 > this.maxx) { b.x2 = this.maxx; }
                    if (b.y2 > this.maxy) { b.y2 = this.maxy; }
                }
                b.w = b.x2 - b.x;
                b.h = b.y2 - b.y;
                return b;
            },
            refresh: function(sel){
                this.elw = sel.core.container.width();
                this.elh = sel.core.container.height();
                this.minx = 0 + sel.edge.w;
                this.miny = 0 + sel.edge.n;
                this.maxx = this.elw + sel.edge.e;
                this.maxy = this.elh + sel.edge.s;
            }
        });
        Jcrop.registerFilter('constrain',ConstrainFilter);

        /**
         *  ExtentFilter
         *  a filter to implement minimum or maximum size
         */
        var ExtentFilter = function(){
            this.core = null;
        };
        $.extend(ExtentFilter.prototype,{
            tag: 'extent',
            priority: 12,
            offsetFromCorner: function(corner,box,b){
                var w = box[0], h = box[1];
                switch(corner){
                    case 'bl': return [ b.x2 - w, b.y, w, h ];
                    case 'tl': return [ b.x2 - w , b.y2 - h, w, h ];
                    case 'br': return [ b.x, b.y, w, h ];
                    case 'tr': return [ b.x, b.y2 - h, w, h ];
                }
            },
            getQuadrant: function(s){
                var relx = s.opposite[0]-s.offsetx
                var rely = s.opposite[1]-s.offsety;

                if ((relx < 0) && (rely < 0)) return 'br';
                else if ((relx >= 0) && (rely >= 0)) return 'tl';
                else if ((relx < 0) && (rely >= 0)) return 'tr';
                return 'bl';
            },
            filter: function(b,ord,sel){

                if (ord == 'move') return b;

                var w = b.w, h = b.h, st = sel.state, r = this.limits;
                var quad = st? this.getQuadrant(st): 'br';

                if (r.minw && (w < r.minw)) w = r.minw;
                if (r.minh && (h < r.minh)) h = r.minh;
                if (r.maxw && (w > r.maxw)) w = r.maxw;
                if (r.maxh && (h > r.maxh)) h = r.maxh;

                if ((w == b.w) && (h == b.h)) return b;

                return Jcrop.wrapFromXywh(this.offsetFromCorner(quad,[w,h],b));
            },
            refresh: function(sel){
                this.elw = sel.core.container.width();
                this.elh = sel.core.container.height();

                this.limits = {
                    minw: sel.minSize[0],
                    minh: sel.minSize[1],
                    maxw: sel.maxSize[0],
                    maxh: sel.maxSize[1]
                };
            }
        });
        Jcrop.registerFilter('extent',ExtentFilter);


        /**
         *  GridFilter
         *  a rudimentary grid effect
         */
        var GridFilter = function(){
            this.stepx = 1;
            this.stepy = 1;
            this.core = null;
        };
        $.extend(GridFilter.prototype,{
            tag: 'grid',
            priority: 19,
            filter: function(b){

                var n = {
                    x: Math.round(b.x / this.stepx) * this.stepx,
                    y: Math.round(b.y / this.stepy) * this.stepy,
                    x2: Math.round(b.x2 / this.stepx) * this.stepx,
                    y2: Math.round(b.y2 / this.stepy) * this.stepy
                };

                n.w = n.x2 - n.x;
                n.h = n.y2 - n.y;

                return n;
            }
        });
        Jcrop.registerFilter('grid',GridFilter);


        /**
         *  RatioFilter
         *  implements aspectRatio locking
         */
        var RatioFilter = function(){
            this.ratio = 0;
            this.core = null;
        };
        $.extend(RatioFilter.prototype,{
            tag: 'ratio',
            priority: 15,
            offsetFromCorner: function(corner,box,b){
                var w = box[0], h = box[1];
                switch(corner){
                    case 'bl': return [ b.x2 - w, b.y, w, h ];
                    case 'tl': return [ b.x2 - w , b.y2 - h, w, h ];
                    case 'br': return [ b.x, b.y, w, h ];
                    case 'tr': return [ b.x, b.y2 - h, w, h ];
                }
            },
            getBoundRatio: function(b,quad){
                var box = Jcrop.getLargestBox(this.ratio,b.w,b.h);
                return Jcrop.wrapFromXywh(this.offsetFromCorner(quad,box,b));
            },
            getQuadrant: function(s){
                var relx = s.opposite[0]-s.offsetx
                var rely = s.opposite[1]-s.offsety;

                if ((relx < 0) && (rely < 0)) return 'br';
                else if ((relx >= 0) && (rely >= 0)) return 'tl';
                else if ((relx < 0) && (rely >= 0)) return 'tr';
                return 'bl';
            },
            filter: function(b,ord,sel){

                if (!this.ratio) return b;

                var rt = b.w / b.h;
                var st = sel.state;

                var quad = st? this.getQuadrant(st): 'br';
                ord = ord || 'se';

                if (ord == 'move') return b;

                switch(ord) {
                    case 'n':
                        b.x2 = this.elw;
                        b.w = b.x2 - b.x;
                        quad = 'tr';
                        break;
                    case 's':
                        b.x2 = this.elw;
                        b.w = b.x2 - b.x;
                        quad = 'br';
                        break;
                    case 'e':
                        b.y2 = this.elh;
                        b.h = b.y2 - b.y;
                        quad = 'br';
                        break;
                    case 'w':
                        b.y2 = this.elh;
                        b.h = b.y2 - b.y;
                        quad = 'bl';
                        break;
                }

                return this.getBoundRatio(b,quad);
            },
            refresh: function(sel){
                this.ratio = sel.aspectRatio;
                this.elw = sel.core.container.width();
                this.elh = sel.core.container.height();
            }
        });
        Jcrop.registerFilter('ratio',RatioFilter);


        /**
         *  RoundFilter
         *  rounds coordinate values to integers
         */
        var RoundFilter = function(){
            this.core = null;
        };
        $.extend(RoundFilter.prototype,{
            tag: 'round',
            priority: 90,
            filter: function(b){

                var n = {
                    x: Math.round(b.x),
                    y: Math.round(b.y),
                    x2: Math.round(b.x2),
                    y2: Math.round(b.y2)
                };

                n.w = n.x2 - n.x;
                n.h = n.y2 - n.y;

                return n;
            }
        });
        Jcrop.registerFilter('round',RoundFilter);


        /**
         *  ShadeFilter
         *  A filter that implements div-based shading on any element
         *
         *  The shading you see is actually four semi-opaque divs
         *  positioned inside the container, around the selection
         */
        var ShadeFilter = function(opacity,color){
            this.color = color || 'black';
            this.opacity = opacity || 0.5;
            this.core = null;
            this.shades = {};
        };
        $.extend(ShadeFilter.prototype,{
            tag: 'shader',
            fade: true,
            fadeEasing: 'swing',
            fadeSpeed: 320,
            priority: 95,
            init: function(){
                var t = this;

                if (!t.attached) {
                    t.visible = false;

                    t.container = $('<div />').addClass(t.core.opt.css_shades)
                        .prependTo(this.core.container).hide();

                    t.elh = this.core.container.height();
                    t.elw = this.core.container.width();

                    t.shades = {
                        top: t.createShade(),
                        right: t.createShade(),
                        left: t.createShade(),
                        bottom: t.createShade()
                    };

                    t.attached = true;
                }
            },
            destroy: function(){
                this.container.remove();
            },
            setColor: function(color,instant){
                var t = this;

                if (color == t.color) return t;

                this.color = color;
                var colorfade = Jcrop.supportsColorFade();
                $.each(t.shades,function(u,i){
                    if (!t.fade || instant || !colorfade) i.css('backgroundColor',color);
                    else i.animate({backgroundColor:color},{queue:false,duration:t.fadeSpeed,easing:t.fadeEasing});
                });
                return t;
            },
            setOpacity: function(opacity,instant){
                var t = this;

                if (opacity == t.opacity) return t;

                t.opacity = opacity;
                $.each(t.shades,function(u,i){
                    if (!t.fade || instant) i.css({opacity:opacity});
                    else i.animate({opacity:opacity},{queue:false,duration:t.fadeSpeed,easing:t.fadeEasing});
                });
                return t;
            },
            createShade: function(){
                return $('<div />').css({
                    position: 'absolute',
                    backgroundColor: this.color,
                    opacity: this.opacity
                }).appendTo(this.container);
            },
            refresh: function(sel){
                var m = this.core, s = this.shades;

                this.setColor(sel.bgColor?sel.bgColor:this.core.opt.bgColor);
                this.setOpacity(sel.bgOpacity?sel.bgOpacity:this.core.opt.bgOpacity);

                this.elh = m.container.height();
                this.elw = m.container.width();
                s.right.css('height',this.elh+'px');
                s.left.css('height',this.elh+'px');
            },
            filter: function(b,ord,sel){

                if (!sel.active) return b;

                var t = this,
                    s = t.shades;

                s.top.css({
                    left: Math.round(b.x)+'px',
                    width: Math.round(b.w)+'px',
                    height: Math.round(b.y)+'px'
                });
                s.bottom.css({
                    top: Math.round(b.y2)+'px',
                    left: Math.round(b.x)+'px',
                    width: Math.round(b.w)+'px',
                    height: (t.elh-Math.round(b.y2))+'px'
                });
                s.right.css({
                    left: Math.round(b.x2)+'px',
                    width: (t.elw-Math.round(b.x2))+'px'
                });
                s.left.css({
                    width: Math.round(b.x)+'px'
                });

                if (!t.visible) {
                    t.container.show();
                    t.visible = true;
                }

                return b;
            }
        });
        Jcrop.registerFilter('shader',ShadeFilter);


        /**
         *  CanvasAnimator
         *  manages smooth cropping animation
         *
         *  This object is called internally to manage animation.
         *  An in-memory div is animated and a progress callback
         *  is used to update the selection coordinates of the
         *  visible selection in realtime.
         */
        var CanvasAnimator = function(stage){
            this.stage = stage;
            this.core = stage.core;
            this.cloneStagePosition();
        };

        CanvasAnimator.prototype = {

            cloneStagePosition: function(){
                var s = this.stage;
                this.angle = s.angle;
                this.scale = s.scale;
                this.offset = s.offset;
            },

            getElement: function(){
                var s = this.stage;

                return $('<div />')
                    .css({
                        position: 'absolute',
                        top: s.offset[0]+'px',
                        left: s.offset[1]+'px',
                        width: s.angle+'px',
                        height: s.scale+'px'
                    });
            },

            animate: function(cb){
                var t = this;

                this.scale = this.stage.boundScale(this.scale);
                t.stage.triggerEvent('croprotstart');

                t.getElement().animate({
                    top: t.offset[0]+'px',
                    left: t.offset[1]+'px',
                    width: t.angle+'px',
                    height: t.scale+'px'
                },{
                    easing: t.core.opt.animEasing,
                    duration: t.core.opt.animDuration,
                    complete: function(){
                        t.stage.triggerEvent('croprotend');
                        (typeof cb == 'function') && cb.call(this);
                    },
                    progress: function(anim){
                        var props = {}, i, tw = anim.tweens;

                        for(i=0;i<tw.length;i++){
                            props[tw[i].prop] = tw[i].now; }

                        t.stage.setAngle(props.width)
                            .setScale(props.height)
                            .setOffset(props.top,props.left)
                            .redraw();
                    }
                });
            }

        };
        Jcrop.stage.Canvas.prototype.getAnimator = function(){
            return new CanvasAnimator(this);
        };
        Jcrop.registerComponent('CanvasAnimator',CanvasAnimator);


        /**
         *  CropAnimator
         *  manages smooth cropping animation
         *
         *  This object is called internally to manage animation.
         *  An in-memory div is animated and a progress callback
         *  is used to update the selection coordinates of the
         *  visible selection in realtime.
         */
            // var CropAnimator = function(selection){{{
        var CropAnimator = function(selection){
                this.selection = selection;
                this.core = selection.core;
            };
        // }}}

        CropAnimator.prototype = {

            getElement: function(){
                var b = this.selection.get();

                return $('<div />')
                    .css({
                        position: 'absolute',
                        top: b.y+'px',
                        left: b.x+'px',
                        width: b.w+'px',
                        height: b.h+'px'
                    });
            },

            animate: function(x,y,w,h,cb){
                var t = this;

                t.selection.allowResize(false);

                t.getElement().animate({
                    top: y+'px',
                    left: x+'px',
                    width: w+'px',
                    height: h+'px'
                },{
                    easing: t.core.opt.animEasing,
                    duration: t.core.opt.animDuration,
                    complete: function(){
                        t.selection.allowResize(true);
                        cb && cb.call(this);
                    },
                    progress: function(anim){
                        var props = {}, i, tw = anim.tweens;

                        for(i=0;i<tw.length;i++){
                            props[tw[i].prop] = tw[i].now; }

                        var b = {
                            x: parseInt(props.left),
                            y: parseInt(props.top),
                            w: parseInt(props.width),
                            h: parseInt(props.height)
                        };

                        b.x2 = b.x + b.w;
                        b.y2 = b.y + b.h;

                        t.selection.updateRaw(b,'se');
                    }
                });
            }

        };
        Jcrop.registerComponent('Animator',CropAnimator);


        /**
         *  DragState
         *  an object that handles dragging events
         *
         *  This object is used by the built-in selection object to
         *  track a dragging operation on a selection
         */
            // var DragState = function(e,selection,ord){{{
        var DragState = function(e,selection,ord){
                var t = this;

                t.x = e.pageX;
                t.y = e.pageY;

                t.selection = selection;
                t.eventTarget = selection.core.opt.dragEventTarget;
                t.orig = selection.get();

                selection.callFilterFunction('refresh');

                var p = selection.core.container.position();
                t.elx = p.left;
                t.ely = p.top;

                t.offsetx = 0;
                t.offsety = 0;
                t.ord = ord;
                t.opposite = t.getOppositeCornerOffset();

                t.initEvents(e);

            };
        // }}}

        DragState.prototype = {
            // getOppositeCornerOffset: function(){{{
            // Calculate relative offset of locked corner
            getOppositeCornerOffset: function(){

                var o = this.orig;
                var relx = this.x - this.elx - o.x;
                var rely = this.y - this.ely - o.y;

                switch(this.ord){
                    case 'nw':
                    case 'w':
                        return [ o.w - relx, o.h - rely ];
                        return [ o.x + o.w, o.y + o.h ];

                    case 'sw':
                        return [ o.w - relx, -rely ];
                        return [ o.x + o.w, o.y ];

                    case 'se':
                    case 's':
                    case 'e':
                        return [ -relx, -rely ];
                        return [ o.x, o.y ];

                    case 'ne':
                    case 'n':
                        return [ -relx, o.h - rely ];
                        return [ o.w, o.y + o.h ];
                }

                return [ null, null ];
            },
            // }}}
            // initEvents: function(e){{{
            initEvents: function(e){
                $(this.eventTarget)
                    .on('mousemove.jcrop',this.createDragHandler())
                    .on('mouseup.jcrop',this.createStopHandler());
            },
            // }}}
            // dragEvent: function(e){{{
            dragEvent: function(e){
                this.offsetx = e.pageX - this.x;
                this.offsety = e.pageY - this.y;
                this.selection.updateRaw(this.getBox(),this.ord);
            },
            // }}}
            // endDragEvent: function(e){{{
            endDragEvent: function(e){
                var sel = this.selection;
                sel.core.container.removeClass('jcrop-dragging');
                sel.element.trigger('cropend',[sel,sel.core.unscale(sel.get())]);
                sel.focus();
            },
            // }}}
            // createStopHandler: function(){{{
            createStopHandler: function(){
                var t = this;
                return function(e){
                    $(t.eventTarget).off('.jcrop');
                    t.endDragEvent(e);
                    return false;
                };
            },
            // }}}
            // createDragHandler: function(){{{
            createDragHandler: function(){
                var t = this;
                return function(e){
                    t.dragEvent(e);
                    return false;
                };
            },
            // }}}
            //update: function(x,y){{{
            update: function(x,y){
                var t = this;
                t.offsetx = x - t.x;
                t.offsety = y - t.y;
            },
            //}}}
            //resultWrap: function(d){{{
            resultWrap: function(d){
                var b = {
                    x: Math.min(d[0],d[2]),
                    y: Math.min(d[1],d[3]),
                    x2: Math.max(d[0],d[2]),
                    y2: Math.max(d[1],d[3])
                };

                b.w = b.x2 - b.x;
                b.h = b.y2 - b.y;

                return b;
            },
            //}}}
            //getBox: function(){{{
            getBox: function(){
                var t = this;
                var o = t.orig;
                var _c = { x2: o.x + o.w, y2: o.y + o.h };
                switch(t.ord){
                    case 'n': return t.resultWrap([ o.x, t.offsety + o.y, _c.x2, _c.y2 ]);
                    case 's': return t.resultWrap([ o.x, o.y, _c.x2, t.offsety + _c.y2 ]);
                    case 'e': return t.resultWrap([ o.x, o.y, t.offsetx + _c.x2, _c.y2 ]);
                    case 'w': return t.resultWrap([ o.x + t.offsetx, o.y, _c.x2, _c.y2 ]);
                    case 'sw': return t.resultWrap([ t.offsetx + o.x, o.y, _c.x2, t.offsety + _c.y2 ]);
                    case 'se': return t.resultWrap([ o.x, o.y, t.offsetx + _c.x2, t.offsety + _c.y2 ]);
                    case 'ne': return t.resultWrap([ o.x, t.offsety + o.y, t.offsetx + _c.x2, _c.y2 ]);
                    case 'nw': return t.resultWrap([ t.offsetx + o.x, t.offsety + o.y, _c.x2, _c.y2 ]);
                    case 'move':
                        _c.nx = o.x + t.offsetx;
                        _c.ny = o.y + t.offsety;
                        return t.resultWrap([ _c.nx, _c.ny, _c.nx + o.w, _c.ny + o.h ]);
                }
            }
            //}}}
        };
        Jcrop.registerComponent('DragState',DragState);


        /**
         *  EventManager
         *  provides internal event support
         */
        var EventManager = function(core){
            this.core = core;
        };
        EventManager.prototype = {
            on: function(n,cb){ $(this).on(n,cb); },
            off: function(n){ $(this).off(n); },
            trigger: function(n){ $(this).trigger(n); }
        };
        Jcrop.registerComponent('EventManager',EventManager);


        /**
         * Image Loader
         * Reliably pre-loads images
         */
            // var ImageLoader = function(src,element,cb){{{
        var ImageLoader = function(src,element,cb){
                this.src = src;
                if (!element) element = new Image;
                this.element = element;
                this.callback = cb;
                this.load();
            };
        // }}}

        $.extend(ImageLoader,{
            // attach: function(el,cb){{{
            attach: function(el,cb){
                return new ImageLoader(el.src,el,cb);
            },
            // }}}
            // prototype: {{{
            prototype: {
                getDimensions: function(){
                    var el = this.element;
                    console.log('获得元素高宽');
                    if ($(el).width())
                        return [ $(el).width(), $(el).height() ];

                    if (el.naturalWidth)
                        return [ el.naturalWidth, el. naturalHeight ];

                    if (el.width)
                        return [ el.width, el.height ];

                    return null;
                },
                fireCallback: function(){
                    this.element.onload = null;
                    if (typeof this.callback == 'function')
                        this.callback.apply(this,this.getDimensions());
                },
                isLoaded: function(){
                    return this.element.complete;
                },
                load: function(){
                    var t = this;
                    var el = t.element;

                    el.src = t.src;

                    if (t.isLoaded()) t.fireCallback();
                    else t.element.onload = function(e){
                        t.fireCallback();
                    };
                }
            }
            // }}}
        });
        Jcrop.registerComponent('ImageLoader',ImageLoader);


        /**
         * JcropTouch
         * Detects and enables mobile touch support
         */
            // var JcropTouch = function(core){{{
        var JcropTouch = function(core){
                this.core = core;
                this.init();
            };
        // }}}

        $.extend(JcropTouch,{
            // support: function(){{{
            support: function(){
                if(('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch)
                    return true;
            },
            // }}}
            prototype: {
                // init: function(){{{
                init: function(){
                    var t = this,
                        p = $.Jcrop.component.DragState.prototype;

                    // A bit of an ugly hack to make sure we modify prototype
                    // only once, store a key on the prototype
                    if (!p.touch) {
                        t.initEvents();
                        t.shimDragState();
                        t.shimStageDrag();
                        p.touch = true;
                    }
                },
                // }}}
                // shimDragState: function(){{{
                shimDragState: function(){
                    var t = this;
                    $.Jcrop.component.DragState.prototype.initEvents = function(e){

                        // Attach subsequent drag event handlers based on initial
                        // event type - avoids collecting "pseudo-mouse" events
                        // generated by some mobile browsers in some circumstances
                        if (e.type.substr(0,5) == 'touch') {

                            $(this.eventTarget)
                                .on('touchmove.jcrop.jcrop-touch',t.dragWrap(this.createDragHandler()))
                                .on('touchend.jcrop.jcrop-touch',this.createStopHandler());

                        }

                        // For other events, use the mouse handlers that
                        // the default DragState.initEvents() method sets...
                        else {

                            $(this.eventTarget)
                                .on('mousemove.jcrop',this.createDragHandler())
                                .on('mouseup.jcrop',this.createStopHandler());

                        }

                    };
                },
                // }}}
                // shimStageDrag: function(){{{
                shimStageDrag: function(){
                    this.core.container
                        .addClass('jcrop-touch')
                        .on('touchstart.jcrop.jcrop-stage',this.dragWrap(this.core.ui.manager.startDragHandler()));
                },
                // }}}
                // dragWrap: function(cb){{{
                dragWrap: function(cb){
                    return function(e){
                        e.preventDefault();
                        e.stopPropagation();
                        if (e.type.substr(0,5) == 'touch') {
                            e.pageX = e.originalEvent.changedTouches[0].pageX;
                            e.pageY = e.originalEvent.changedTouches[0].pageY;
                            return cb(e);
                        }
                        return false;
                    };
                },
                // }}}
                // initEvents: function(){{{
                initEvents: function(){
                    var t = this, c = t.core;

                    c.container.on(
                        'touchstart.jcrop.jcrop-touch',
                        '.'+c.opt.css_drag,
                        t.dragWrap(c.startDrag())
                    );
                }
                // }}}
            }
        });
        Jcrop.registerComponent('Touch',JcropTouch);


        /**
         *  KeyWatcher
         *  provides keyboard support
         */
            // var KeyWatcher = function(core){{{
        var KeyWatcher = function(core){
                this.core = core;
                this.init();
            };
        // }}}
        $.extend(KeyWatcher,{
            // defaults: {{{
            defaults: {
                eventName: 'keydown.jcrop',
                passthru: [ 9 ],
                debug: false
            },
            // }}}
            prototype: {
                // init: function(){{{
                init: function(){
                    $.extend(this,KeyWatcher.defaults);
                    this.enable();
                },
                // }}}
                // disable: function(){{{
                disable: function(){
                    this.core.container.off(this.eventName);
                },
                // }}}
                // enable: function(){{{
                enable: function(){
                    var t = this, m = t.core;
                    m.container.on(t.eventName,function(e){
                        var nudge = e.shiftKey? 16: 2;

                        if ($.inArray(e.keyCode,t.passthru) >= 0)
                            return true;

                        switch(e.keyCode){
                            case 37: m.nudge(-nudge,0); break;
                            case 38: m.nudge(0,-nudge); break;
                            case 39: m.nudge(nudge,0); break;
                            case 40: m.nudge(0,nudge); break;

                            case 46:
                            case 8:
                                m.requestDelete();
                                return false;
                                break;

                            default:
                                if (t.debug) console.log('keycode: ' + e.keyCode);
                                break;
                        }

                        if (!e.metaKey && !e.ctrlKey)
                            e.preventDefault();
                    });
                }
                // }}}
            }
        });
        Jcrop.registerComponent('Keyboard',KeyWatcher);


        /**
         * Selection
         * Built-in selection object
         */
        var Selection = function(){};

        $.extend(Selection,{
            // defaults: {{{
            defaults: {
                minSize: [ 8, 8 ],
                maxSize: [ 0, 0 ],
                aspectRatio: 0,
                edge: { n: 0, s: 0, e: 0, w: 0 },
                bgColor: null,
                bgOpacity: null,
                last: null,

                state: null,
                active: true,
                linked: true,
                canDelete: true,
                canDrag: true,
                canResize: true,
                canSelect: true
            },
            // }}}
            prototype: {
                // init: function(core){{{
                init: function(core){
                    this.core = core;
                    this.startup();
                    this.linked = this.core.opt.linked;
                    this.attach();
                    this.setOptions(this.core.opt);
                    core.container.trigger('cropcreate',[this]);
                },
                // }}}
                // attach: function(){{{
                attach: function(){
                    // For extending init() sequence
                },
                // }}}
                // startup: function(){{{
                startup: function(){
                    var t = this, o = t.core.opt;
                    $.extend(t,Selection.defaults);
                    t.filter = t.core.getDefaultFilters();

                    t.element = $('<div />').addClass(o.css_selection).data({ selection: t });
                    t.frame = $('<button />').addClass(o.css_button).data('ord','move').attr('type','button');
                    t.element.append(t.frame).appendTo(t.core.container);

                    // IE background/draggable hack
                    if (t.core.opt.is_msie) t.frame.css({
                        opacity: 0,
                        backgroundColor: 'white'
                    });

                    t.insertElements();

                    // Bind focus and blur events for this selection
                    t.frame.on('focus.jcrop',function(e){
                        t.core.setSelection(t);
                        t.element.trigger('cropfocus',t);
                        t.element.addClass('jcrop-focus');
                    }).on('blur.jcrop',function(e){
                        t.element.removeClass('jcrop-focus');
                        t.element.trigger('cropblur',t);
                    });
                },
                // }}}
                // propagate: [{{{
                propagate: [
                    'canDelete', 'canDrag', 'canResize', 'canSelect',
                    'minSize', 'maxSize', 'aspectRatio', 'edge'
                ],
                // }}}
                // setOptions: function(opt){{{
                setOptions: function(opt){
                    Jcrop.propagate(this.propagate,opt,this);
                    this.refresh();
                    return this;
                },
                // }}}
                // refresh: function(){{{
                refresh: function(){
                    this.allowResize();
                    this.allowDrag();
                    this.allowSelect();
                    this.callFilterFunction('refresh');
                    this.updateRaw(this.get(),'se');
                },
                // }}}
                // callFilterFunction: function(f,args){{{
                callFilterFunction: function(f,args){
                    for(var i=0;i<this.filter.length;i++)
                        if (this.filter[i][f]) this.filter[i][f](this);
                    return this;
                },
                // }}}
                //addFilter: function(filter){{{
                addFilter: function(filter){
                    filter.core = this.core;
                    if (!this.hasFilter(filter)) {
                        this.filter.push(filter);
                        this.sortFilters();
                        if (filter.init) filter.init();
                        this.refresh();
                    }
                },
                //}}}
                // hasFilter: function(filter){{{
                hasFilter: function(filter){
                    var i, f = this.filter, n = [];
                    for(i=0;i<f.length;i++) if (f[i] === filter) return true;
                },
                // }}}
                // sortFilters: function(){{{
                sortFilters: function(){
                    this.filter.sort(
                        function(x,y){ return x.priority - y.priority; }
                    );
                },
                // }}}
                //clearFilters: function(){{{
                clearFilters: function(){
                    var i, f = this.filter;

                    for(var i=0;i<f.length;i++)
                        if (f[i].destroy) f[i].destroy();

                    this.filter = [];
                },
                //}}}
                // removeFiltersByTag: function(tag){{{
                removeFilter: function(tag){
                    var i, f = this.filter, n = [];

                    for(var i=0;i<f.length;i++)
                        if ((f[i].tag && (f[i].tag == tag)) || (tag === f[i])){
                            if (f[i].destroy) f[i].destroy();
                        }
                        else n.push(f[i]);

                    this.filter = n;
                },
                // }}}
                // runFilters: function(b,ord){{{
                runFilters: function(b,ord){
                    for(var i=0;i<this.filter.length;i++)
                        b = this.filter[i].filter(b,ord,this);
                    return b;
                },
                // }}}
                //endDrag: function(){{{
                endDrag: function(){
                    if (this.state) {
                        $(document.body).off('.jcrop');
                        this.focus();
                        this.state = null;
                    }
                },
                //}}}
                // startDrag: function(e,ord){{{
                startDrag: function(e,ord){
                    var t = this;
                    var m = t.core;

                    ord = ord || $(e.target).data('ord');

                    this.focus();

                    if ((ord == 'move') && t.element.hasClass(t.core.opt.css_nodrag))
                        return false;

                    this.state = new Jcrop.component.DragState(e,this,ord);
                    return false;
                },
                // }}}
                // allowSelect: function(v){{{
                allowSelect: function(v){
                    if (v === undefined) v = this.canSelect;

                    if (v && this.canSelect) this.frame.attr('disabled',false);
                    else this.frame.attr('disabled','disabled');

                    return this;
                },
                // }}}
                // allowDrag: function(v){{{
                allowDrag: function(v){
                    var t = this, o = t.core.opt;
                    if (v == undefined) v = t.canDrag;

                    if (v && t.canDrag) t.element.removeClass(o.css_nodrag);
                    else t.element.addClass(o.css_nodrag);

                    return this;
                },
                // }}}
                // allowResize: function(v){{{
                allowResize: function(v){
                    var t = this, o = t.core.opt;
                    if (v == undefined) v = t.canResize;

                    if (v && t.canResize) t.element.removeClass(o.css_noresize);
                    else t.element.addClass(o.css_noresize);

                    return this;
                },
                // }}}
                // remove: function(){{{
                remove: function(){
                    this.element.trigger('cropremove',this);
                    this.element.remove();
                },
                // }}}
                // toBack: function(){{{
                toBack: function(){
                    this.active = false;
                    this.element.removeClass('jcrop-current jcrop-focus');
                },
                // }}}
                // toFront: function(){{{
                toFront: function(){
                    this.active = true;
                    this.element.addClass('jcrop-current');
                    this.callFilterFunction('refresh');
                    this.refresh();
                },
                // }}}
                // redraw: function(b){{{
                redraw: function(b){
                    this.moveTo(b.x,b.y);
                    this.resize(b.w,b.h);
                    this.last = b;
                    return this;
                },
                // }}}
                // update: function(b,ord){{{
                update: function(b,ord){
                    return this.updateRaw(this.core.scale(b),ord);
                },
                // }}}
                // update: function(b,ord){{{
                updateRaw: function(b,ord){
                    b = this.runFilters(b,ord);
                    this.redraw(b);
                    this.element.trigger('cropmove',[this,this.core.unscale(b)]);
                    return this;
                },
                // }}}
                // animateTo: function(box,cb){{{
                animateTo: function(box,cb){
                    var ca = new Jcrop.component.Animator(this),
                        b = this.core.scale(Jcrop.wrapFromXywh(box));

                    ca.animate(b.x,b.y,b.w,b.h,cb);
                },
                // }}}
                // center: function(instant){{{
                center: function(instant){
                    var b = this.get(), m = this.core;
                    var elw = m.container.width(), elh = m.container.height();
                    var box = [ (elw-b.w)/2, (elh-b.h)/2, b.w, b.h ];
                    return this[instant?'setSelect':'animateTo'](box);
                },
                // }}}
                //createElement: function(type,ord){{{
                createElement: function(type,ord){
                    return $('<div />').addClass(type+' ord-'+ord).data('ord',ord);
                },
                //}}}
                //moveTo: function(x,y){{{
                moveTo: function(x,y){
                    this.element.css({top: y+'px', left: x+'px'});
                },
                //}}}
                // blur: function(){{{
                blur: function(){
                    this.element.blur();
                    return this;
                },
                // }}}
                // focus: function(){{{
                focus: function(){
                    this.core.setSelection(this);
                    this.frame.focus();
                    return this;
                },
                // }}}
                //resize: function(w,h){{{
                resize: function(w,h){
                    this.element.css({width: w+'px', height: h+'px'});
                },
                //}}}
                //get: function(){{{
                get: function(){
                    var b = this.element,
                        o = b.position(),
                        w = b.width(),
                        h = b.height(),
                        rv = { x: o.left, y: o.top };

                    rv.x2 = rv.x + w;
                    rv.y2 = rv.y + h;
                    rv.w = w;
                    rv.h = h;

                    return rv;
                },
                //}}}
                //insertElements: function(){{{
                insertElements: function(){
                    var t = this, i,
                        m = t.core,
                        fr = t.element,
                        o = t.core.opt,
                        b = o.borders,
                        h = o.handles,
                        d = o.dragbars;

                    for(i=0; i<d.length; i++)
                        fr.append(t.createElement(o.css_dragbars,d[i]));

                    for(i=0; i<h.length; i++)
                        fr.append(t.createElement(o.css_handles,h[i]));

                    for(i=0; i<b.length; i++)
                        fr.append(t.createElement(o.css_borders,b[i]));
                }
                //}}}
            }
        });
        Jcrop.registerComponent('Selection',Selection);


        /**
         * StageDrag
         * Facilitates dragging
         */
            // var StageDrag = function(manager,opt){{{
        var StageDrag = function(manager,opt){
                $.extend(this,StageDrag.defaults,opt || {});
                this.manager = manager;
                this.core = manager.core;
            };
        // }}}
        // StageDrag.defaults = {{{
        StageDrag.defaults = {
            offset: [ -8, -8 ],
            active: true,
            minsize: [ 20, 20 ]
        };
        // }}}

        $.extend(StageDrag.prototype,{
            // start: function(e){{{
            start: function(e){
                var c = this.core;

                // Do nothing if allowSelect is off
                if (!c.opt.allowSelect) return;

                // Also do nothing if we can't draw any more selections
                if (c.opt.multi && c.opt.multiMax && (c.ui.multi.length >= c.opt.multiMax)) return false;

                // calculate a few variables for this drag operation
                var o = $(e.currentTarget).offset();
                var origx = e.pageX - o.left + this.offset[0];
                var origy = e.pageY - o.top + this.offset[1];
                var m = c.ui.multi;

                // Determine newly dragged crop behavior if multi disabled
                if (!c.opt.multi) {
                    // For multiCleaanup true, remove all existing selections
                    if (c.opt.multiCleanup){
                        for(var i=0;i<m.length;i++) m[i].remove();
                        c.ui.multi = [];
                    }
                    // If not, only remove the currently active selection
                    else {
                        c.removeSelection(c.ui.selection);
                    }
                }

                c.container.addClass('jcrop-dragging');

                // Create the new selection
                var sel = c.newSelection()
                // and position it
                    .updateRaw(Jcrop.wrapFromXywh([origx,origy,1,1]));

                sel.element.trigger('cropstart',[sel,this.core.unscale(sel.get())]);

                return sel.startDrag(e,'se');
            },
            // }}}
            // end: function(x,y){{{
            end: function(x,y){
                this.drag(x,y);
                var b = this.sel.get();

                this.core.container.removeClass('jcrop-dragging');

                if ((b.w < this.minsize[0]) || (b.h < this.minsize[1]))
                    this.core.requestDelete();

                else this.sel.focus();
            }
            // }}}
        });
        Jcrop.registerComponent('StageDrag',StageDrag);


        /**
         * StageManager
         * Provides basic stage-specific functionality
         */
            // var StageManager = function(core){{{
        var StageManager = function(core){
                this.core = core;
                this.ui = core.ui;
                this.init();
            };
        // }}}

        $.extend(StageManager.prototype,{
            // init: function(){{{
            init: function(){
                this.setupEvents();
                this.dragger = new StageDrag(this);
            },
            // }}}
            // tellConfigUpdate: function(options){{{
            tellConfigUpdate: function(options){
                for(var i=0,m=this.ui.multi,l=m.length;i<l;i++)
                    if (m[i].setOptions && (m[i].linked || (this.core.opt.linkCurrent && m[i] == this.ui.selection)))
                        m[i].setOptions(options);
            },
            // }}}
            // startDragHandler: function(){{{
            startDragHandler: function(){
                var t = this;
                return function(e){
                    if (!e.button || t.core.opt.is_ie_lt9) return t.dragger.start(e);
                };
            },
            // }}}
            // removeEvents: function(){{{
            removeEvents: function(){
                this.core.event.off('.jcrop-stage');
                this.core.container.off('.jcrop-stage');
            },
            // }}}
            // shimLegacyHandlers: function(options){{{
            // This method uses the legacyHandlers configuration object to
            // gracefully wrap old-style Jcrop events with new ones
            shimLegacyHandlers: function(options){
                var _x = {}, core = this.core, tmp;

                $.each(core.opt.legacyHandlers,function(k,i){
                    if (k in options) {
                        tmp = options[k];
                        core.container.off('.jcrop-'+k)
                            .on(i+'.jcrop.jcrop-'+k,function(e,s,c){
                                tmp.call(core,c);
                            });
                        delete options[k];
                    }
                });
            },
            // }}}
            // setupEvents: function(){{{
            setupEvents: function(){
                var t = this, c = t.core;

                c.event.on('configupdate.jcrop-stage',function(e){
                    t.shimLegacyHandlers(c.opt);
                    t.tellConfigUpdate(c.opt)
                    c.container.trigger('cropconfig',[c,c.opt]);
                });

                this.core.container
                    .on('mousedown.jcrop.jcrop-stage',this.startDragHandler());
            }
            // }}}
        });
        Jcrop.registerComponent('StageManager',StageManager);


        var Thumbnailer = function(){
        };

        $.extend(Thumbnailer,{
            defaults: {
                // Set to a specific Selection object
                // If this value is set, the preview will only track that Selection
                selection: null,

                fading: true,
                fadeDelay: 1000,
                fadeDuration: 1000,
                autoHide: false,
                width: 80,
                height: 80,
                _hiding: null
            },

            prototype: {
                recopyCanvas: function(){
                    var s = this.core.ui.stage, cxt = s.context;
                    this.context.putImageData(cxt.getImageData(0,0,s.canvas.width,s.canvas.height),0,0);
                },
                init: function(core,options){
                    var t = this;
                    this.core = core;
                    $.extend(this,Thumbnailer.defaults,options);
                    t.initEvents();
                    t.refresh();
                    t.insertElements();
                    if (t.selection) {
                        t.renderSelection(t.selection);
                        t.selectionTarget = t.selection.element[0];
                    } else if (t.core.ui.selection) {
                        t.renderSelection(t.core.ui.selection);
                    }

                    if (t.core.ui.stage.canvas) {
                        t.context = t.preview[0].getContext('2d');
                        t.core.container.on('cropredraw',function(e){
                            t.recopyCanvas();
                            t.refresh();
                        });
                    }
                },
                updateImage: function(imgel){
                    this.preview.remove();
                    this.preview = $($.Jcrop.imageClone(imgel));
                    this.element.append(this.preview);
                    this.refresh();
                    return this;
                },
                insertElements: function(){
                    this.preview = $($.Jcrop.imageClone(this.core.ui.stage.imgsrc));

                    this.element = $('<div />').addClass('jcrop-thumb')
                        .width(this.width).height(this.height)
                        .append(this.preview)
                        .appendTo(this.core.container);
                },
                resize: function(w,h){
                    this.width = w;
                    this.height = h;
                    this.element.width(w).height(h);
                    this.renderCoords(this.last);
                },
                refresh: function(){
                    this.cw = (this.core.opt.xscale * this.core.container.width());
                    this.ch = (this.core.opt.yscale * this.core.container.height());
                    if (this.last) {
                        this.renderCoords(this.last);
                    }
                },
                renderCoords: function(c){
                    var rx = this.width / c.w;
                    var ry = this.height / c.h;

                    this.preview.css({
                        width: Math.round(rx * this.cw) + 'px',
                        height: Math.round(ry * this.ch) + 'px',
                        marginLeft: '-' + Math.round(rx * c.x) + 'px',
                        marginTop: '-' + Math.round(ry * c.y) + 'px'
                    });

                    this.last = c;
                    return this;
                },
                renderSelection: function(s){
                    return this.renderCoords(s.core.unscale(s.get()));
                },
                selectionStart: function(s){
                    this.renderSelection(s);
                },
                show: function(){
                    if (this._hiding) clearTimeout(this._hiding);

                    if (!this.fading) this.element.stop().css({ opacity: 1 });
                    else this.element.stop().animate({ opacity: 1 },{ duration: 80, queue: false });
                },
                hide: function(){
                    var t = this;
                    if (!t.fading) t.element.hide();
                    else t._hiding = setTimeout(function(){
                        t._hiding = null;
                        t.element.stop().animate({ opacity: 0 },{ duration: t.fadeDuration, queue: false });
                    },t.fadeDelay);
                },
                initEvents: function(){
                    var t = this;
                    t.core.container.on('croprotstart croprotend cropimage cropstart cropmove cropend',function(e,s,c){
                        if (t.selectionTarget && (t.selectionTarget !== e.target)) return false;

                        switch(e.type){

                            case 'cropimage':
                                t.updateImage(c);
                                break;

                            case 'cropstart':
                                t.selectionStart(s);
                            case 'croprotstart':
                                t.show();
                                break;

                            case 'cropend':
                                t.renderCoords(c);
                            case 'croprotend':
                                if (t.autoHide) t.hide();
                                break;

                            case 'cropmove':
                                t.renderCoords(c);
                                break;
                        }
                    });
                }
            }
        });
        Jcrop.registerComponent('Thumbnailer',Thumbnailer);


        /**
         * DialDrag component
         * This is a little hacky, it was adapted from some previous/old code
         * Plan to update this API in the future
         */
        var DialDrag = function() { };

        DialDrag.prototype = {

            init: function(core,actuator,callback){
                var that = this;

                if (!actuator) actuator = core.container;
                this.$btn = $(actuator);
                this.$targ = $(actuator);
                this.core = core;

                this.$btn
                    .addClass('dialdrag')
                    .on('mousedown.dialdrag',this.mousedown())
                    .data('dialdrag',this);

                if (!$.isFunction(callback)) callback = function(){ };
                this.callback = callback;
                this.ondone = callback;
            },

            remove: function(){
                this.$btn
                    .removeClass('dialdrag')
                    .off('.dialdrag')
                    .data('dialdrag',null);
                return this;
            },

            setTarget: function(obj){
                this.$targ = $(obj);
                return this;
            },

            getOffset: function(){
                var targ = this.$targ, pos = targ.offset();
                return [
                    pos.left + (targ.width()/2),
                    pos.top + (targ.height()/2)
                ];
            },

            relMouse: function(e){
                var x = e.pageX - this.offset[0],
                    y = e.pageY - this.offset[1],
                    ang = Math.atan2(y,x) * (180 / Math.PI),
                    vec = Math.sqrt(Math.pow(x,2)+Math.pow(y,2));
                return [ x, y, ang, vec ];
            },

            mousedown: function(){
                var that = this;

                function mouseUp(e){
                    $(window).off('.dialdrag');
                    that.ondone.call(that,that.relMouse(e));
                    that.core.container.trigger('croprotend');
                }

                function mouseMove(e){
                    that.callback.call(that,that.relMouse(e));
                }

                return function(e) {
                    that.offset = that.getOffset();
                    var rel = that.relMouse(e);
                    that.angleOffset = -that.core.ui.stage.angle+rel[2];
                    that.distOffset = rel[3];
                    that.dragOffset = [rel[0],rel[1]];
                    that.core.container.trigger('croprotstart');

                    $(window)
                        .on('mousemove.dialdrag',mouseMove)
                        .on('mouseup.dialdrag',mouseUp);

                    that.callback.call(that,that.relMouse(e));

                    return false;
                };
            }

        };
        Jcrop.registerComponent('DialDrag',DialDrag);


        /////////////////////////////////
        // DEFAULT SETTINGS

        Jcrop.defaults = {

            // Selection Behavior
            edge: { n: 0, s: 0, e: 0, w: 0 },
            setSelect: null,
            linked: true,
            linkCurrent: true,
            canDelete: true,
            canSelect: true,
            canDrag: true,
            canResize: true,

            // Component constructors
            eventManagerComponent:  Jcrop.component.EventManager,
            keyboardComponent:      Jcrop.component.Keyboard,
            dragstateComponent:     Jcrop.component.DragState,
            stagemanagerComponent:  Jcrop.component.StageManager,
            animatorComponent:      Jcrop.component.Animator,
            selectionComponent:     Jcrop.component.Selection,

            // This is a function that is called, which returns a stage object
            stageConstructor:       Jcrop.stageConstructor,

            // Stage Behavior
            allowSelect: true,
            multi: false,
            multiMax: false,
            multiCleanup: true,
            animation: true,
            animEasing: 'swing',
            animDuration: 400,
            fading: true,
            fadeDuration: 300,
            fadeEasing: 'swing',
            bgColor: 'black',
            bgOpacity: .5,

            // Startup options
            applyFilters: [ 'constrain', 'extent', 'backoff', 'ratio', 'shader', 'round' ],
            borders:  [ 'e', 'w', 's', 'n' ],
            handles:  [ 'n', 's', 'e', 'w', 'sw', 'ne', 'nw', 'se' ],
            dragbars: [ 'n', 'e', 'w', 's' ],

            dragEventTarget: window,

            xscale: 1,
            yscale: 1,

            boxWidth: null,
            boxHeight: null,

            // CSS Classes
            // @todo: These need to be moved to top-level object keys
            // for better customization. Currently if you try to extend one
            // via an options object to Jcrop, it will wipe out all
            // the others you don't specify. Be careful for now!
            css_nodrag: 'jcrop-nodrag',
            css_drag: 'jcrop-drag',
            css_container: 'jcrop-active',
            css_shades: 'jcrop-shades',
            css_selection: 'jcrop-selection',
            css_borders: 'jcrop-border',
            css_handles: 'jcrop-handle jcrop-drag',
            css_button: 'jcrop-box jcrop-drag',
            css_noresize: 'jcrop-noresize',
            css_dragbars: 'jcrop-dragbar jcrop-drag',

            legacyHandlers: {
                onChange: 'cropmove',
                onSelect: 'cropend'
            }

        };


        // Jcrop API methods
        $.extend(Jcrop.prototype,{
            //init: function(){{{
            init: function(){
                this.event = new this.opt.eventManagerComponent(this);
                this.ui.keyboard = new this.opt.keyboardComponent(this);
                this.ui.manager = new this.opt.stagemanagerComponent(this);
                this.applyFilters();

                if ($.Jcrop.supportsTouch)
                    new $.Jcrop.component.Touch(this);

                this.initEvents();
            },
            //}}}
            // applySizeConstraints: function(){{{
            applySizeConstraints: function(){
                var o = this.opt,
                    img = this.opt.imgsrc;

                if (img){

                    var iw = img.naturalWidth || img.width,
                        ih = img.naturalHeight || img.height,
                        bw = o.boxWidth || iw,
                        bh = o.boxHeight || ih;

                    if (img && ((iw > bw) || (ih > bh))){
                        var bx = Jcrop.getLargestBox(iw/ih,bw,bh);
                        $(img).width(bx[0]).height(bx[1]);
                        this.resizeContainer(bx[0],bx[1]);
                        this.opt.xscale = iw / bx[0];
                        this.opt.yscale = ih / bx[1];
                    }

                }

                if (this.opt.trueSize){
                    var dw = this.opt.trueSize[0];
                    var dh = this.opt.trueSize[1];
                    var cs = this.getContainerSize();
                    this.opt.xscale = dw / cs[0];
                    this.opt.yscale = dh / cs[1];
                }
            },
            // }}}
            initComponent: function(name){
                if (Jcrop.component[name]) {
                    var args = Array.prototype.slice.call(arguments);
                    var obj = new Jcrop.component[name];
                    args.shift();
                    args.unshift(this);
                    obj.init.apply(obj,args);
                    return obj;
                }
            },
            // setOptions: function(opt){{{
            setOptions: function(opt,proptype){

                if (!$.isPlainObject(opt)) opt = {};

                $.extend(this.opt,opt);

                // Handle a setSelect value
                if (this.opt.setSelect) {

                    // If there is no current selection
                    // passing setSelect will create one
                    if (!this.ui.multi.length)
                        this.newSelection();

                    // Use these values to update the current selection
                    this.setSelect(this.opt.setSelect);

                    // Set to null so it doesn't get called again
                    this.opt.setSelect = null;
                }

                this.event.trigger('configupdate');
                return this;
            },
            // }}}
            //destroy: function(){{{
            destroy: function(){
                if (this.opt.imgsrc) {
                    this.container.before(this.opt.imgsrc);
                    this.container.remove();
                    $(this.opt.imgsrc).removeData('Jcrop').show();
                } else {
                    // @todo: more elegant destroy() process for non-image containers
                    this.container.remove();
                }
            },
            // }}}
            // applyFilters: function(){{{
            applyFilters: function(){
                var obj;
                for(var i=0,f=this.opt.applyFilters,l=f.length; i<l; i++){
                    if ($.Jcrop.filter[f[i]])
                        obj = new $.Jcrop.filter[f[i]];
                    obj.core = this;
                    if (obj.init) obj.init();
                    this.filter[f[i]] = obj;
                }
            },
            // }}}
            // getDefaultFilters: function(){{{
            getDefaultFilters: function(){
                var rv = [];

                for(var i=0,f=this.opt.applyFilters,l=f.length; i<l; i++)
                    if(this.filter.hasOwnProperty(f[i]))
                        rv.push(this.filter[f[i]]);

                rv.sort(function(x,y){ return x.priority - y.priority; });
                return rv;
            },
            // }}}
            // setSelection: function(sel){{{
            setSelection: function(sel){
                var m = this.ui.multi;
                var n = [];
                for(var i=0;i<m.length;i++) {
                    if (m[i] !== sel) n.push(m[i]);
                    m[i].toBack();
                }
                n.unshift(sel);
                this.ui.multi = n;
                this.ui.selection = sel;
                sel.toFront();
                return sel;
            },
            // }}}
            // getSelection: function(raw){{{
            getSelection: function(raw){
                var b = this.ui.selection.get();
                return b;
            },
            // }}}
            // newSelection: function(){{{
            newSelection: function(sel){
                if (!sel)
                    sel = new this.opt.selectionComponent();

                sel.init(this);
                this.setSelection(sel);

                return sel;
            },
            // }}}
            // hasSelection: function(sel){{{
            hasSelection: function(sel){
                for(var i=0;i<this.ui.multi;i++)
                    if (sel === this.ui.multi[i]) return true;
            },
            // }}}
            // removeSelection: function(sel){{{
            removeSelection: function(sel){
                var i, n = [], m = this.ui.multi;
                for(var i=0;i<m.length;i++){
                    if (sel !== m[i])
                        n.push(m[i]);
                    else m[i].remove();
                }
                return this.ui.multi = n;
            },
            // }}}
            //addFilter: function(filter){{{
            addFilter: function(filter){
                for(var i=0,m=this.ui.multi,l=m.length; i<l; i++)
                    m[i].addFilter(filter);

                return this;
            },
            //}}}
            // removeFiltersByTag: function(tag){{{
            removeFilter: function(filter){
                for(var i=0,m=this.ui.multi,l=m.length; i<l; i++)
                    m[i].removeFilter(filter);

                return this;
            },
            // }}}
            // blur: function(){{{
            blur: function(){
                this.ui.selection.blur();
                return this;
            },
            // }}}
            // focus: function(){{{
            focus: function(){
                this.ui.selection.focus();
                return this;
            },
            // }}}
            //initEvents: function(){{{
            initEvents: function(){
                var t = this;
                t.container.on('selectstart',function(e){ return false; })
                    .on('mousedown','.'+t.opt.css_drag,t.startDrag());
            },
            //}}}
            // maxSelect: function(){{{
            maxSelect: function(){
                this.setSelect([0,0,this.elw,this.elh]);
            },
            // }}}
            // nudge: function(x,y){{{
            nudge: function(x,y){
                var s = this.ui.selection, b = s.get();

                b.x += x;
                b.x2 += x;
                b.y += y;
                b.y2 += y;

                if (b.x < 0) { b.x2 = b.w; b.x = 0; }
                else if (b.x2 > this.elw) { b.x2 = this.elw; b.x = b.x2 - b.w; }

                if (b.y < 0) { b.y2 = b.h; b.y = 0; }
                else if (b.y2 > this.elh) { b.y2 = this.elh; b.y = b.y2 - b.h; }

                s.element.trigger('cropstart',[s,this.unscale(b)]);
                s.updateRaw(b,'move');
                s.element.trigger('cropend',[s,this.unscale(b)]);
            },
            // }}}
            // refresh: function(){{{
            refresh: function(){
                for(var i=0,s=this.ui.multi,l=s.length;i<l;i++)
                    s[i].refresh();
            },
            // }}}
            // blurAll: function(){{{
            blurAll: function(){
                var m = this.ui.multi;
                for(var i=0;i<m.length;i++) {
                    if (m[i] !== sel) n.push(m[i]);
                    m[i].toBack();
                }
            },
            // }}}
            // scale: function(b){{{
            scale: function(b){
                var xs = this.opt.xscale,
                    ys = this.opt.yscale;

                return {
                    x: b.x / xs,
                    y: b.y / ys,
                    x2: b.x2 / xs,
                    y2: b.y2 / ys,
                    w: b.w / xs,
                    h: b.h / ys
                };
            },
            // }}}
            // unscale: function(b){{{
            unscale: function(b){
                var xs = this.opt.xscale,
                    ys = this.opt.yscale;

                return {
                    x: b.x * xs,
                    y: b.y * ys,
                    x2: b.x2 * xs,
                    y2: b.y2 * ys,
                    w: b.w * xs,
                    h: b.h * ys
                };
            },
            // }}}
            // requestDelete: function(){{{
            requestDelete: function(){
                if ((this.ui.multi.length > 1) && (this.ui.selection.canDelete))
                    return this.deleteSelection();
            },
            // }}}
            // deleteSelection: function(){{{
            deleteSelection: function(){
                if (this.ui.selection) {
                    this.removeSelection(this.ui.selection);
                    if (this.ui.multi.length) this.ui.multi[0].focus();
                    this.ui.selection.refresh();
                }
            },
            // }}}
            // animateTo: function(box){{{
            animateTo: function(box){
                if (this.ui.selection)
                    this.ui.selection.animateTo(box);
                return this;
            },
            // }}}
            // setselect: function(box){{{
            setSelect: function(box){
                if (this.ui.selection)
                    this.ui.selection.update(Jcrop.wrapFromXywh(box));
                return this;
            },
            // }}}
            //startDrag: function(){{{
            startDrag: function(){
                var t = this;
                return function(e){
                    var $targ = $(e.target);
                    var selection = $targ.closest('.'+t.opt.css_selection).data('selection');
                    var ord = $targ.data('ord');
                    t.container.trigger('cropstart',[selection,t.unscale(selection.get())]);
                    selection.startDrag(e,ord);
                    return false;
                };
            },
            //}}}
            // getContainerSize: function(){{{
            getContainerSize: function(){
                console.log(this.container);
                return [ this.container.width(), this.container.height() ];
            },
            // }}}
            // resizeContainer: function(w,h){{{
            resizeContainer: function(w,h){
                this.container.width(w).height(h);
                this.refresh();
            },
            // }}}
            // setImage: function(src,cb){{{
            setImage: function(src,cb){
                var t = this, targ = t.opt.imgsrc;

                if (!targ) return false;

                new $.Jcrop.component.ImageLoader(src,null,function(w,h){
                    t.resizeContainer(w,h);

                    targ.src = src;
                    $(targ).width(w).height(h);
                    t.applySizeConstraints();
                    t.refresh();
                    t.container.trigger('cropimage',[t,targ]);

                    if (typeof cb == 'function')
                        cb.call(t,w,h);
                });
            },
            // }}}
            // update: function(b){{{
            update: function(b){
                if (this.ui.selection)
                    this.ui.selection.update(b);
            }
            // }}}
        });

        // Jcrop jQuery plugin function
        $.fn.Jcrop = function(options,callback){
            options = options || {};

            var first = this.eq(0).data('Jcrop');
            var args = Array.prototype.slice.call(arguments);

            // Return API if requested
            if (options == 'api') { return first; }

            // Allow calling API methods (with arguments)
            else if (first && (typeof options == 'string')) {

                // Call method if it exists
                if (first[options]) {
                    args.shift();
                    first[options].apply(first,args);
                    return first;
                }

                // Unknown input/method does not exist
                return false;
            }

            // Otherwise, loop over selected elements
            this.each(function(){
                var t = this, $t = $(this);
                var exists = $t.data('Jcrop');
                var obj;

                // If Jcrop already exists on this element only setOptions()
                if (exists)
                    exists.setOptions(options);

                else {

                    if (!options.stageConstructor)
                        options.stageConstructor = $.Jcrop.stageConstructor;

                    options.stageConstructor(this,options,function(stage,options){
                        var selection = options.setSelect;
                        if (selection) delete(options.setSelect);

                        var obj = $.Jcrop.attach(stage.element,options);
                        console.log(stage);
                        console.log('调用方法创建');
                        if (typeof stage.attach == 'function')
                            stage.attach(obj);
                        console.log('调用方法');
                        $t.data('Jcrop',obj);

                        if (selection) {
                            obj.newSelection();
                            obj.setSelect(selection);
                        }

                        if (typeof callback == 'function')
                            callback.call(obj);
                    });
                }

                return this;
            });
        };

        /* Modernizr 2.7.1 (Custom Build) | MIT & BSD
         * Build: http://modernizr.com/download/#-csstransforms-canvas-canvastext-draganddrop-inlinesvg-svg-svgclippaths-touch-teststyles-testprop-testallprops-hasevent-prefixes-domprefixes-url_data_uri
         */
        ;

        var Modernizr = (function( window, document, undefined ) {

            var version = '2.7.1',

                Modernizr = {},


                docElement = document.documentElement,

                mod = 'modernizr',
                modElem = document.createElement(mod),
                mStyle = modElem.style,

                inputElem  ,


                toString = {}.toString,

                prefixes = ' -webkit- -moz- -o- -ms- '.split(' '),



                omPrefixes = 'Webkit Moz O ms',

                cssomPrefixes = omPrefixes.split(' '),

                domPrefixes = omPrefixes.toLowerCase().split(' '),

                ns = {'svg': 'http://www.w3.org/2000/svg'},

                tests = {},
                inputs = {},
                attrs = {},

                classes = [],

                slice = classes.slice,

                featureName,


                injectElementWithStyles = function( rule, callback, nodes, testnames ) {

                    var style, ret, node, docOverflow,
                        div = document.createElement('div'),
                        body = document.body,
                        fakeBody = body || document.createElement('body');

                    if ( parseInt(nodes, 10) ) {
                        while ( nodes-- ) {
                            node = document.createElement('div');
                            node.id = testnames ? testnames[nodes] : mod + (nodes + 1);
                            div.appendChild(node);
                        }
                    }

                    style = ['&#173;','<style id="s', mod, '">', rule, '</style>'].join('');
                    div.id = mod;
                    (body ? div : fakeBody).innerHTML += style;
                    fakeBody.appendChild(div);
                    if ( !body ) {
                        fakeBody.style.background = '';
                        fakeBody.style.overflow = 'hidden';
                        docOverflow = docElement.style.overflow;
                        docElement.style.overflow = 'hidden';
                        docElement.appendChild(fakeBody);
                    }

                    ret = callback(div, rule);
                    if ( !body ) {
                        fakeBody.parentNode.removeChild(fakeBody);
                        docElement.style.overflow = docOverflow;
                    } else {
                        div.parentNode.removeChild(div);
                    }

                    return !!ret;

                },



                isEventSupported = (function() {

                    var TAGNAMES = {
                        'select': 'input', 'change': 'input',
                        'submit': 'form', 'reset': 'form',
                        'error': 'img', 'load': 'img', 'abort': 'img'
                    };

                    function isEventSupported( eventName, element ) {

                        element = element || document.createElement(TAGNAMES[eventName] || 'div');
                        eventName = 'on' + eventName;

                        var isSupported = eventName in element;

                        if ( !isSupported ) {
                            if ( !element.setAttribute ) {
                                element = document.createElement('div');
                            }
                            if ( element.setAttribute && element.removeAttribute ) {
                                element.setAttribute(eventName, '');
                                isSupported = is(element[eventName], 'function');

                                if ( !is(element[eventName], 'undefined') ) {
                                    element[eventName] = undefined;
                                }
                                element.removeAttribute(eventName);
                            }
                        }

                        element = null;
                        return isSupported;
                    }
                    return isEventSupported;
                })(),


                _hasOwnProperty = ({}).hasOwnProperty, hasOwnProp;

            if ( !is(_hasOwnProperty, 'undefined') && !is(_hasOwnProperty.call, 'undefined') ) {
                hasOwnProp = function (object, property) {
                    return _hasOwnProperty.call(object, property);
                };
            }
            else {
                hasOwnProp = function (object, property) {
                    return ((property in object) && is(object.constructor.prototype[property], 'undefined'));
                };
            }


            if (!Function.prototype.bind) {
                Function.prototype.bind = function bind(that) {

                    var target = this;

                    if (typeof target != "function") {
                        throw new TypeError();
                    }

                    var args = slice.call(arguments, 1),
                        bound = function () {

                            if (this instanceof bound) {

                                var F = function(){};
                                F.prototype = target.prototype;
                                var self = new F();

                                var result = target.apply(
                                    self,
                                    args.concat(slice.call(arguments))
                                );
                                if (Object(result) === result) {
                                    return result;
                                }
                                return self;

                            } else {

                                return target.apply(
                                    that,
                                    args.concat(slice.call(arguments))
                                );

                            }

                        };

                    return bound;
                };
            }

            function setCss( str ) {
                mStyle.cssText = str;
            }

            function setCssAll( str1, str2 ) {
                return setCss(prefixes.join(str1 + ';') + ( str2 || '' ));
            }

            function is( obj, type ) {
                return typeof obj === type;
            }

            function contains( str, substr ) {
                return !!~('' + str).indexOf(substr);
            }

            function testProps( props, prefixed ) {
                for ( var i in props ) {
                    var prop = props[i];
                    if ( !contains(prop, "-") && mStyle[prop] !== undefined ) {
                        return prefixed == 'pfx' ? prop : true;
                    }
                }
                return false;
            }

            function testDOMProps( props, obj, elem ) {
                for ( var i in props ) {
                    var item = obj[props[i]];
                    if ( item !== undefined) {

                        if (elem === false) return props[i];

                        if (is(item, 'function')){
                            return item.bind(elem || obj);
                        }

                        return item;
                    }
                }
                return false;
            }

            function testPropsAll( prop, prefixed, elem ) {

                var ucProp  = prop.charAt(0).toUpperCase() + prop.slice(1),
                    props   = (prop + ' ' + cssomPrefixes.join(ucProp + ' ') + ucProp).split(' ');

                if(is(prefixed, "string") || is(prefixed, "undefined")) {
                    return testProps(props, prefixed);

                } else {
                    props = (prop + ' ' + (domPrefixes).join(ucProp + ' ') + ucProp).split(' ');
                    return testDOMProps(props, prefixed, elem);
                }
            }



            tests['canvas'] = function() {
                var elem = document.createElement('canvas');
                return !!(elem.getContext && elem.getContext('2d'));
            };

            tests['canvastext'] = function() {
                return !!(Modernizr['canvas'] && is(document.createElement('canvas').getContext('2d').fillText, 'function'));
            };
            tests['touch'] = function() {
                var bool;

                if(('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) {
                    bool = true;
                } else {
                    injectElementWithStyles(['@media (',prefixes.join('touch-enabled),('),mod,')','{#modernizr{top:9px;position:absolute}}'].join(''), function( node ) {
                        bool = node.offsetTop === 9;
                    });
                }

                return bool;
            };

            tests['draganddrop'] = function() {
                var div = document.createElement('div');
                return ('draggable' in div) || ('ondragstart' in div && 'ondrop' in div);
            };


            tests['csstransforms'] = function() {
                return !!testPropsAll('transform');
            };


            tests['svg'] = function() {
                return !!document.createElementNS && !!document.createElementNS(ns.svg, 'svg').createSVGRect;
            };

            tests['inlinesvg'] = function() {
                var div = document.createElement('div');
                div.innerHTML = '<svg/>';
                return (div.firstChild && div.firstChild.namespaceURI) == ns.svg;
            };



            tests['svgclippaths'] = function() {
                return !!document.createElementNS && /SVGClipPath/.test(toString.call(document.createElementNS(ns.svg, 'clipPath')));
            };

            for ( var feature in tests ) {
                if ( hasOwnProp(tests, feature) ) {
                    featureName  = feature.toLowerCase();
                    Modernizr[featureName] = tests[feature]();

                    classes.push((Modernizr[featureName] ? '' : 'no-') + featureName);
                }
            }



            Modernizr.addTest = function ( feature, test ) {
                if ( typeof feature == 'object' ) {
                    for ( var key in feature ) {
                        if ( hasOwnProp( feature, key ) ) {
                            Modernizr.addTest( key, feature[ key ] );
                        }
                    }
                } else {

                    feature = feature.toLowerCase();

                    if ( Modernizr[feature] !== undefined ) {
                        return Modernizr;
                    }

                    test = typeof test == 'function' ? test() : test;

                    if (typeof enableClasses !== "undefined" && enableClasses) {
                        docElement.className += ' ' + (test ? '' : 'no-') + feature;
                    }
                    Modernizr[feature] = test;

                }

                return Modernizr;
            };


            setCss('');
            modElem = inputElem = null;


            Modernizr._version      = version;

            Modernizr._prefixes     = prefixes;
            Modernizr._domPrefixes  = domPrefixes;
            Modernizr._cssomPrefixes  = cssomPrefixes;


            Modernizr.hasEvent      = isEventSupported;

            Modernizr.testProp      = function(prop){
                return testProps([prop]);
            };

            Modernizr.testAllProps  = testPropsAll;


            Modernizr.testStyles    = injectElementWithStyles;
            return Modernizr;

        })(window, window.document);
    // data uri test.
    // https://github.com/Modernizr/Modernizr/issues/14

    // This test is asynchronous. Watch out.


    // in IE7 in HTTPS this can cause a Mixed Content security popup.
    //  github.com/Modernizr/Modernizr/issues/362
    // To avoid that you can create a new iframe and inject this.. perhaps..


        (function(){

            var datauri = new Image();


            datauri.onerror = function() {
                Modernizr.addTest('datauri', function () { return false; });
            };
            datauri.onload = function() {
                Modernizr.addTest('datauri', function () { return (datauri.width == 1 && datauri.height == 1); });
            };

            datauri.src = "";

        })();
        ;

        // Attach to jQuery object
        $.Jcrop = Jcrop;

        $.Jcrop.supportsCanvas = Modernizr.canvas;
        $.Jcrop.supportsCanvasText = Modernizr.canvastext;
        $.Jcrop.supportsDragAndDrop = Modernizr.draganddrop;
        $.Jcrop.supportsDataURI = Modernizr.datauri;
        $.Jcrop.supportsSVG = Modernizr.svg;
        $.Jcrop.supportsInlineSVG = Modernizr.inlinesvg;
        $.Jcrop.supportsSVGClipPaths = Modernizr.svgclippaths;
        $.Jcrop.supportsCSSTransforms = Modernizr.csstransforms;
        $.Jcrop.supportsTouch = Modernizr.touch;

    })(jQuery);
});
